const moment = require('moment')
const WebSocket = require('ws')
const pako = require('pako')
const log4js = require('log4js')
const config = require('../config/index')
const Redis = require('ioredis')
const redis = new Redis(config.redis)
const request = require('request-promise')

// 配置log4js
log4js.configure(config.log4js)
const logger = log4js.getLogger('火币Pro WebSocket监控')

const wsUrl = 'wss://api.huobi.pro/ws'
const symbolsUrl = 'https://api.huobipro.com/v1/common/symbols'
const klineUrl = 'https://api.huobipro.com/market/history/kline'
const symbols = []
let recordList = {}

;(async () => {
  try {
    await getSymbols()
    await getDayOpenPrice()
    initWs()
  } catch (e) {
    logger.error('程序初始化失败：' + e.message)
  }
})()

async function wait (ms) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, ms)
  })
}

/**
 * 获取火币所有交易对
 * @returns {Promise<Array>}
 */
async function getSymbols () {
  let {status, data: list} = await request({
    url: symbolsUrl,
    json: true
  })
  if (status === 'ok') {
    for (let item of list) {
      item['quote-currency'] === 'usdt' && symbols.push(item['base-currency'] + item['quote-currency'])
    }
  } else {
    throw new Error('获取交易对失败')
  }
}

/**
 * 获取每日开盘价
 * @returns {Promise<void>}
 */
async function getDayOpenPrice () {
  for (let symbol of symbols) {
    // 处理初始化后没有记录
    if (!recordList[symbol]) {
      recordList[symbol] = {}
    }
    try {
      let {status, data: [kline]} = await request({
        url: klineUrl,
        qs: {period: '1day', size: 1, symbol: symbol},
        json: true
      })
      if (status === 'ok') {
        recordList[symbol].dayOpen = kline.open
        console.log(symbol, recordList[symbol])
      }
      // 等待100ms
      await wait(100)
    } catch (e) {
      recordList[symbol].dayOpen = 0
      logger.error('获取每日开盘价失败[' + symbol + ']' + e.message)
    }
  }
}

/**
 * 初始化websocket
 */
function initWs () {
  let ws = new WebSocket(wsUrl)
  let pingTimer = null
  let reTimer = null
  ws.on('open', () => {
    console.log('open')
    subscribe(ws)
    ws.isAlive = true
    // 每10秒ping一次
    pingTimer = setInterval(() => {
      if (ws.isAlive === false) {
        clearInterval(pingTimer)
        return ws.terminate()
      }
      ws.isAlive = false
      heartbeat()
    }, 10000)
  })
  ws.on('message', (data) => {
    let text = pako.inflate(data, {
      to: 'string'
    })
    let msg = JSON.parse(text)
    if (msg.ping) {
      ws.send(JSON.stringify({
        pong: msg.ping
      }))
    } else if (msg.pong) {
      ws.isAlive = true
    } else if (msg.tick) {
      handle(msg)
    } else {
      console.log(text)
    }
  })

  ws.on('close', () => {
    console.log('close')
    clearInterval(pingTimer)
    clearTimeout(reTimer)
    reTimer = setTimeout(() => {
      initWs()
    }, 2000)
  })

  ws.on('error', err => {
    console.log('error', err)
    logger.error(err)
    clearInterval(pingTimer)
    clearTimeout(reTimer)
    reTimer = setTimeout(() => {
      initWs()
    }, 2000)
  })

  function heartbeat () {
    let ping = Date.now()
    ws.send(JSON.stringify({
      ping: ping
    }))
  }
}

function handle (data) {
  let symbol = data.ch.split('.')[1]
  let channel = data.ch.split('.')[2]
  if (channel === 'kline') {
    let record = recordList[symbol]
    // 新K线  初始化涨幅为0  记录前一分钟的K线
    if (!record.tick || record.tick.id !== data.tick.id) {
      record.prevTick = record.tick
      record.percent = 0
    }

    record.tick = data.tick

    // 开盘价
    let open = data.tick.open
    // 收盘价
    let close = data.tick.close
    // 涨幅
    let percent = ((close - open) / open * 100).toFixed(2)

    // 凌晨00:00 一天最开始的一条K线  重新设置每日开盘价
    if (moment.unix(data.tick.id).utcOffset(8).format('HH:mm') === '00:00' && record.dayOpen !== open) {
      record.dayOpen = open
    }

    // 如果当前价格小于今日开盘价忽略 或者 当前价格小于前一分钟的最高价（震荡）忽略
    if (close < record.dayOpen || (record.prevTick && close < record.prevTick.high)) {
      return
    }
    // 一分钟内涨幅每达到1% 2% 3% ... 各提示一次
    if (parseInt(percent) > record.percent) {
      record.percent = parseInt(percent)
      let now = moment().utcOffset(8).format('YYYY-MM-DD HH:mm:ss')
      console.log(`币种：${symbol}, 涨幅：${percent}, 时间：${now}`)
      redis.publish('news', JSON.stringify({
        type: 1,
        source: '火币Pro',
        percent: percent,
        symbol: symbol.toUpperCase(),
        time: now,
        content: `${symbol.toUpperCase()}一分钟内涨幅：${percent}%\n当前价格：${close}`
      }))
    }
  }
}

/**
 * 订阅K线
 * @param ws
 */
function subscribe (ws) {
  for (let symbol of symbols) {
    ws.send(JSON.stringify({
      'sub': `market.${symbol}.kline.1min`,
      'id': `${symbol}`
    }))
  }
}
